#ifndef _thread_pool_HPP
#define _thread_pool_HPP

#include <vector>
#include <deque>
#include <thread>
#include <functional>
#include <mutex>
#include <condition_variable>

//!
//! convenience macro to log with file and line information
//!
#ifdef __SOLA_LOGGING_ENABLED
#define __SOLA_LOG(level, msg) sola::level(msg, __FILE__, __LINE__);
#else
#define __SOLA_LOG(level, msg)
#endif /* __SOLA_LOGGING_ENABLED */

using namespace std;

namespace sola
{

    class logger_iface
    {
    public:
        //! ctor
        logger_iface(void) = default;
        //! dtor
        virtual ~logger_iface(void) = default;

        //! copy ctor
        logger_iface(const logger_iface&) = default;
        //! assignment operator
        logger_iface& operator=(const logger_iface&) = default;

    public:
        //!
        //! debug logging
        //!
        //! \param msg message to be logged
        //! \param file file from which the message is coming
        //! \param line line in the file of the message
        //!
        virtual void debug(const std::string& msg, const std::string& file, std::size_t line) = 0;

        //!
        //! info logging
        //!
        //! \param msg message to be logged
        //! \param file file from which the message is coming
        //! \param line line in the file of the message
        //!
        virtual void info(const std::string& msg, const std::string& file, std::size_t line) = 0;

        //!
        //! warn logging
        //!
        //! \param msg message to be logged
        //! \param file file from which the message is coming
        //! \param line line in the file of the message
        //!
        virtual void warn(const std::string& msg, const std::string& file, std::size_t line) = 0;

        //!
        //! error logging
        //!
        //! \param msg message to be logged
        //! \param file file from which the message is coming
        //! \param line line in the file of the message
        //!
        virtual void error(const std::string& msg, const std::string& file, std::size_t line) = 0;
    };

    //!
    //! default logger class provided by the library
    //!
    class logger : public logger_iface
    {
    public:
        //!
        //! log level
        //!
        enum class log_level {
            error = 0,
            warn  = 1,
            info  = 2,
            debug = 3
        };

    public:
        //! ctor
        logger(log_level level = log_level::info);
        //! dtor
        ~logger(void) = default;

        // 禁止拷贝复制和复制操作
        //! copy ctor
        logger(const logger&) = delete;
        //! assignment operator
        logger& operator=(const logger&) = delete;

    public:
        //!
        //! debug logging
        //!
        //! \param msg message to be logged
        //! \param file file from which the message is coming
        //! \param line line in the file of the message
        //!
        void debug(const std::string& msg, const std::string& file, std::size_t line);

        //!
        //! info logging
        //!
        //! \param msg message to be logged
        //! \param file file from which the message is coming
        //! \param line line in the file of the message
        //!
        void info(const std::string& msg, const std::string& file, std::size_t line);

        //!
        //! warn logging
        //!
        //! \param msg message to be logged
        //! \param file file from which the message is coming
        //! \param line line in the file of the message
        //!
        void warn(const std::string& msg, const std::string& file, std::size_t line);

        //!
        //! error logging
        //!
        //! \param msg message to be logged
        //! \param file file from which the message is coming
        //! \param line line in the file of the message
        //!
        void error(const std::string& msg, const std::string& file, std::size_t line);

    private:
        //!
        //! current log level in use
        //!
        log_level m_level;

        //!
        //! mutex used to serialize logs in multithreaded environment
        //!
        std::mutex m_mutex;
    };

    //!
    //! variable containing the current logger
    //! by default, not set (no logs)
    //!
    extern std::unique_ptr<logger_iface> active_logger;

    //!
    //! debug logging
    //! convenience function used internally to call the logger
    //!
    //! \param msg message to be logged
    //! \param file file from which the message is coming
    //! \param line line in the file of the message
    //!
    void debug(const std::string& msg, const std::string& file, std::size_t line);

    //!
    //! info logging
    //! convenience function used internally to call the logger
    //!
    //! \param msg message to be logged
    //! \param file file from which the message is coming
    //! \param line line in the file of the message
    //!
    void info(const std::string& msg, const std::string& file, std::size_t line);

    //!
    //! warn logging
    //! convenience function used internally to call the logger
    //!
    //! \param msg message to be logged
    //! \param file file from which the message is coming
    //! \param line line in the file of the message
    //!
    void warn(const std::string& msg, const std::string& file, std::size_t line);

    //!
    //! error logging
    //! convenience function used internally to call the logger
    //!
    //! \param msg message to be logged
    //! \param file file from which the message is coming
    //! \param line line in the file of the message
    //!
    void error(const std::string& msg, const std::string& file, std::size_t line);


    class thread_pool{
    public:
        typedef std::function<void()> task_t;           // 函数指针, 任务类型的方法是void ()

        thread_pool(int init_size = 3);         // 先默认创建3个线程
        ~thread_pool();

        // 关闭线程
        void stop();
        void add_task(const task_t&);  //thread safe;

    private:
        thread_pool(const thread_pool&);//禁止复制拷贝.
        const thread_pool& operator=(const thread_pool&);

        // 线程是否启动
        bool is_started();
        // 创建线程
        void start();

        // 线程循环
        void thread_loop();

        // 任务出队列
        task_t take();

        typedef std::vector<std::thread*> threads_t;
        typedef std::deque<task_t> tasks_t;

        int m_init_threads_size;

        threads_t m_threads;            // 线程队列
        tasks_t m_tasks;                // 任务队列

        std::mutex m_mutex;
        std::condition_variable m_cond;
        bool m_is_started;
    };

}
#endif

